package com.zzy.socket.nio_selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioSelectorServer {
	public static void main(String[] args) {
		try {
			//通道
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1", 8000));
			serverSocketChannel.configureBlocking(false);

			//选择器
			Selector selector = Selector.open();
			// 注册 channel，并且指定感兴趣的事件是 Accept
			SelectionKey selectionKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

			//缓冲区
			ByteBuffer readBuff = ByteBuffer.allocate(80);
			ByteBuffer writeBuff = ByteBuffer.allocate(80);
			writeBuff.put("大家好(来自服务端)".getBytes());
			// flip()方法可以吧Buffer从写模式切换到读模式。
			writeBuff.flip();

			while (true) {
				//阻塞, 直到有一个channel的状态符合条件
				int ready = selector.select();
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> it = keys.iterator();

				while (it.hasNext()) {
					SelectionKey key = it.next();
					it.remove();

					if (key.isAcceptable()) {
						// 创建新的连接，并且把连接注册到selector上，而且，
						// 声明这个channel只对读操作感兴趣。
						SocketChannel socketChannel = serverSocketChannel.accept();
						socketChannel.configureBlocking(false);
						socketChannel.register(selector, SelectionKey.OP_READ);
					} else if (key.isReadable()) {
						SocketChannel socketChannel = (SocketChannel) key.channel();
						readBuff.clear();
						socketChannel.read(readBuff);
						// flip()方法可以吧Buffer从写模式切换到读模式。
						readBuff.flip();
						System.out.println("服务端:  -----------接收消息-------- :[ " + new String(readBuff.array())+"]");
						key.interestOps(SelectionKey.OP_WRITE);
					} else if (key.isWritable()) {
						writeBuff.rewind();
						SocketChannel socketChannel = (SocketChannel) key.channel();
						socketChannel.write(writeBuff);
						key.interestOps(SelectionKey.OP_READ);
						System.out.println("服务端:  -----------发消息-------- :[" + new String(writeBuff.array())+"]");
					}

				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}